/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2012-2018 DragonBones team and other contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef DRAGONBONES_ANIMATION_H
#define DRAGONBONES_ANIMATION_H

#include "../core/BaseObject.h"

DRAGONBONES_NAMESPACE_BEGIN
/**
 * - The animation player is used to play the animation data and manage the animation states.
 * @see dragonBones.AnimationData
 * @see dragonBones.AnimationState
 * @version DragonBones 3.0
 * @language en_US
 */
/**
 * - 动画播放器用来播放动画数据和管理动画状态。
 * @see dragonBones.AnimationData
 * @see dragonBones.AnimationState
 * @version DragonBones 3.0
 * @language zh_CN
 */
class Animation final : public BaseObject
{
    BIND_CLASS_TYPE_B(Animation);

public:
    /**
     * - The play speed of all animations. [0: Stop, (0~1): Slow, 1: Normal, (1~N): Fast]
     * @default 1.0
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 所有动画的播放速度。 [0: 停止播放, (0~1): 慢速播放, 1: 正常播放, (1~N): 快速播放]
     * @default 1.0
     * @version DragonBones 3.0
     * @language zh_CN
     */
    float timeScale;

private:
    bool _animationDirty;
    float _inheritTimeScale;
    std::vector<std::string> _animationNames;
    std::vector<AnimationState*> _animationStates;
    hlookup::string_map<AnimationData*> _animations;
    Armature* _armature;
    AnimationConfig* _animationConfig;
    AnimationState* _lastAnimationState;

public:
    Animation() : _animationConfig(nullptr) { _onClear(); }
    ~Animation() { _onClear(); }

private:
    void _fadeOut(AnimationConfig* animationConfig);

protected:
    virtual void _onClear() override;

public:
    /**
     * @internal
     */
    void init(Armature* armature);
    /**
     * @internal
     */
    void advanceTime(float passedTime);
    /**
     * - Clear all animations states.
     * @see dragonBones.AnimationState
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 清除所有的动画状态。
     * @see dragonBones.AnimationState
     * @version DragonBones 4.5
     * @language zh_CN
     */
    void reset();
    /**
     * - Pause a specific animation state.
     * @param animationName - The name of animation state. (If not set, it will pause all animations)
     * @see dragonBones.AnimationState
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 暂停指定动画状态的播放。
     * @param animationName - 动画状态名称。 （如果未设置，则暂停所有动画）
     * @see dragonBones.AnimationState
     * @version DragonBones 3.0
     * @language zh_CN
     */
    void stop(std::string_view animationName);
    /**
     * - Play animation with a specific animation config.
     * The API is still in the experimental phase and may encounter bugs or stability or compatibility issues when used.
     * @param animationConfig - The animation config.
     * @returns The playing animation state.
     * @see dragonBones.AnimationConfig
     * @beta
     * @version DragonBones 5.0
     * @language en_US
     */
    /**
     * - 通过指定的动画配置来播放动画。
     * 该 API 仍在实验阶段，使用时可能遭遇 bug 或稳定性或兼容性问题。
     * @param animationConfig - 动画配置。
     * @returns 播放的动画状态。
     * @see dragonBones.AnimationConfig
     * @beta
     * @version DragonBones 5.0
     * @language zh_CN
     */
    AnimationState* playConfig(AnimationConfig* animationConfig);
    /**
     * - Play a specific animation.
     * @param animationName - The name of animation data. (If not set, The default animation will be played, or resume
     * the animation playing from pause status, or replay the last playing animation)
     * @param playTimes - Playing repeat times. [-1: Use default value of the animation data, 0: No end loop playing,
     * [1~N]: Repeat N times] (default: -1)
     * @returns The playing animation state.
     * @example
     * TypeScript style, for reference only.
     * <pre>
     *     armature.animation.play("walk");
     * </pre>
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 播放指定动画。
     * @param animationName - 动画数据名称。
     * （如果未设置，则播放默认动画，或将暂停状态切换为播放状态，或重新播放之前播放的动画）
     * @param playTimes - 循环播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
     * @returns 播放的动画状态。
     * @example
     * TypeScript 风格，仅供参考。
     * <pre>
     *     armature.animation.play("walk");
     * </pre>
     * @version DragonBones 3.0
     * @language zh_CN
     */
    AnimationState* play(std::string_view animationName = "", int playTimes = -1);
    /**
     * - Fade in a specific animation.
     * @param animationName - The name of animation data.
     * @param fadeInTime - The fade in time. [-1: Use the default value of animation data, [0~N]: The fade in time (In
     * seconds)] (Default: -1)
     * @param playTimes - playing repeat times. [-1: Use the default value of animation data, 0: No end loop playing,
     * [1~N]: Repeat N times] (Default: -1)
     * @param layer - The blending layer, the animation states in high level layer will get the blending weights with
     * high priority, when the total blending weights are more than 1.0, there will be no more weights can be allocated
     * to the other animation states. (Default: 0)
     * @param group - The blending group name, it is typically used to specify the substitution of multiple animation
     * states blending. (Default: null)
     * @param fadeOutMode - The fade out mode, which is typically used to specify alternate mode of multiple animation
     * states blending. (Default: AnimationFadeOutMode.SameLayerAndGroup)
     * @returns The playing animation state.
     * @example
     * TypeScript style, for reference only.
     * <pre>
     *     armature.animation.fadeIn("walk", 0.3, 0, 0, "normalGroup").resetToPose = false;
     *     armature.animation.fadeIn("attack", 0.3, 1, 0, "attackGroup").resetToPose = false;
     * </pre>
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 淡入播放指定的动画。
     * @param animationName - 动画数据名称。
     * @param fadeInTime - 淡入时间。 [-1: 使用动画数据默认值, [0~N]: 淡入时间 (以秒为单位)] （默认: -1）
     * @param playTimes - 播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
     * @param layer - 混合图层，图层高的动画状态会优先获取混合权重，当混合权重分配总和超过 1.0
     * 时，剩余的动画状态将不能再获得权重分配。 （默认: 0）
     * @param group - 混合组名称，该属性通常用来指定多个动画状态混合时的相互替换关系。 （默认: null）
     * @param fadeOutMode - 淡出模式，该属性通常用来指定多个动画状态混合时的相互替换模式。 （默认:
     * AnimationFadeOutMode.SameLayerAndGroup）
     * @returns 播放的动画状态。
     * @example
     * TypeScript 风格，仅供参考。
     * <pre>
     *     armature.animation.fadeIn("walk", 0.3, 0, 0, "normalGroup").resetToPose = false;
     *     armature.animation.fadeIn("attack", 0.3, 1, 0, "attackGroup").resetToPose = false;
     * </pre>
     * @version DragonBones 4.5
     * @language zh_CN
     */
    AnimationState* fadeIn(std::string_view animationName,
                           float fadeInTime                 = -1.f,
                           int playTimes                    = -1,
                           int layer                        = 0,
                           std::string_view group           = "",
                           AnimationFadeOutMode fadeOutMode = AnimationFadeOutMode::SameLayerAndGroup);
    /**
     * - Play a specific animation from the specific time.
     * @param animationName - The name of animation data.
     * @param time - The start time point of playing. (In seconds)
     * @param playTimes - Playing repeat times. [-1: Use the default value of animation data, 0: No end loop playing,
     * [1~N]: Repeat N times] (Default: -1)
     * @returns The played animation state.
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 从指定时间开始播放指定的动画。
     * @param animationName - 动画数据名称。
     * @param time - 播放开始的时间。 (以秒为单位)
     * @param playTimes - 循环播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
     * @returns 播放的动画状态。
     * @version DragonBones 4.5
     * @language zh_CN
     */
    AnimationState* gotoAndPlayByTime(std::string_view animationName, float time = 0.f, int playTimes = -1);
    /**
     * - Play a specific animation from the specific frame.
     * @param animationName - The name of animation data.
     * @param frame - The start frame of playing.
     * @param playTimes - Playing repeat times. [-1: Use the default value of animation data, 0: No end loop playing,
     * [1~N]: Repeat N times] (Default: -1)
     * @returns The played animation state.
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 从指定帧开始播放指定的动画。
     * @param animationName - 动画数据名称。
     * @param frame - 播放开始的帧数。
     * @param playTimes - 播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
     * @returns 播放的动画状态。
     * @version DragonBones 4.5
     * @language zh_CN
     */
    AnimationState* gotoAndPlayByFrame(std::string_view animationName, unsigned frame = 0, int playTimes = -1);
    /**
     * - Play a specific animation from the specific progress.
     * @param animationName - The name of animation data.
     * @param progress - The start progress value of playing.
     * @param playTimes - Playing repeat times. [-1: Use the default value of animation data, 0: No end loop playing,
     * [1~N]: Repeat N times] (Default: -1)
     * @returns The played animation state.
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 从指定进度开始播放指定的动画。
     * @param animationName - 动画数据名称。
     * @param progress - 开始播放的进度。
     * @param playTimes - 播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
     * @returns 播放的动画状态。
     * @version DragonBones 4.5
     * @language zh_CN
     */
    AnimationState* gotoAndPlayByProgress(std::string_view animationName, float progress = 0.f, int playTimes = -1);
    /**
     * - Stop a specific animation at the specific time.
     * @param animationName - The name of animation data.
     * @param time - The stop time. (In seconds)
     * @returns The played animation state.
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 在指定时间停止指定动画播放
     * @param animationName - 动画数据名称。
     * @param time - 停止的时间。 (以秒为单位)
     * @returns 播放的动画状态。
     * @version DragonBones 4.5
     * @language zh_CN
     */
    AnimationState* gotoAndStopByTime(std::string_view animationName, float time = 0.f);
    /**
     * - Stop a specific animation at the specific frame.
     * @param animationName - The name of animation data.
     * @param frame - The stop frame.
     * @returns The played animation state.
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 在指定帧停止指定动画的播放
     * @param animationName - 动画数据名称。
     * @param frame - 停止的帧数。
     * @returns 播放的动画状态。
     * @version DragonBones 4.5
     * @language zh_CN
     */
    AnimationState* gotoAndStopByFrame(std::string_view animationName, unsigned frame = 0);
    /**
     * - Stop a specific animation at the specific progress.
     * @param animationName - The name of animation data.
     * @param progress - The stop progress value.
     * @returns The played animation state.
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 在指定的进度停止指定的动画播放。
     * @param animationName - 动画数据名称。
     * @param progress - 停止进度。
     * @returns 播放的动画状态。
     * @version DragonBones 4.5
     * @language zh_CN
     */
    AnimationState* gotoAndStopByProgress(std::string_view animationName, float progress = 0.f);
    /**
     * - Get a specific animation state.
     * @param animationName - The name of animation state.
     * @example
     * TypeScript style, for reference only.
     * <pre>
     *     armature.animation.play("walk");
     *     let walkState = armature.animation.getState("walk");
     *     walkState.timeScale = 0.5;
     * </pre>
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 获取指定的动画状态
     * @param animationName - 动画状态名称。
     * @example
     * TypeScript 风格，仅供参考。
     * <pre>
     *     armature.animation.play("walk");
     *     let walkState = armature.animation.getState("walk");
     *     walkState.timeScale = 0.5;
     * </pre>
     * @version DragonBones 3.0
     * @language zh_CN
     */
    AnimationState* getState(std::string_view animationName) const;
    /**
     * - Check whether a specific animation data is included.
     * @param animationName - The name of animation data.
     * @see dragonBones.AnimationData
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 检查是否包含指定的动画数据
     * @param animationName - 动画数据名称。
     * @see dragonBones.AnimationData
     * @version DragonBones 3.0
     * @language zh_CN
     */
    bool hasAnimation(std::string_view animationName) const;
    /**
     * - Get all the animation states.
     * @version DragonBones 5.1
     * @language en_US
     */
    /**
     * - 获取所有的动画状态
     * @version DragonBones 5.1
     * @language zh_CN
     */
    inline const std::vector<AnimationState*>& getStates() const { return _animationStates; }
    /**
     * - Check whether there is an animation state is playing
     * @see dragonBones.AnimationState
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 检查是否有动画状态正在播放
     * @see dragonBones.AnimationState
     * @version DragonBones 3.0
     * @language zh_CN
     */
    bool isPlaying() const;
    /**
     * - Check whether all the animation states' playing were finished.
     * @see dragonBones.AnimationState
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 检查是否所有的动画状态均已播放完毕。
     * @see dragonBones.AnimationState
     * @version DragonBones 3.0
     * @language zh_CN
     */
    bool isCompleted() const;
    /**
     * - The name of the last playing animation state.
     * @see #lastAnimationState
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 上一个播放的动画状态名称
     * @see #lastAnimationState
     * @version DragonBones 3.0
     * @language zh_CN
     */
    std::string_view getLastAnimationName() const;
    /**
     * - The name of all animation data
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 所有动画数据的名称
     * @version DragonBones 4.5
     * @language zh_CN
     */
    inline const std::vector<std::string>& getAnimationNames() const { return _animationNames; }
    /**
     * - All animation data.
     * @version DragonBones 4.5
     * @language en_US
     */
    /**
     * - 所有的动画数据。
     * @version DragonBones 4.5
     * @language zh_CN
     */
    inline const hlookup::string_map<AnimationData*>& getAnimations() const { return _animations; }
    void setAnimations(const hlookup::string_map<AnimationData*>& value);
    /**
     * - An AnimationConfig instance that can be used quickly.
     * @see dragonBones.AnimationConfig
     * @version DragonBones 5.0
     * @language en_US
     */
    /**
     * - 一个可以快速使用的动画配置实例。
     * @see dragonBones.AnimationConfig
     * @version DragonBones 5.0
     * @language zh_CN
     */
    AnimationConfig* getAnimationConfig() const;
    /**
     * - The last playing animation state
     * @see dragonBones.AnimationState
     * @version DragonBones 3.0
     * @language en_US
     */
    /**
     * - 上一个播放的动画状态
     * @see dragonBones.AnimationState
     * @version DragonBones 3.0
     * @language zh_CN
     */
    inline AnimationState* getLastAnimationState() const { return _lastAnimationState; }
};

DRAGONBONES_NAMESPACE_END
#endif  // DRAGONBONES_ANIMATION_H
